package gridstest;

/*
Copyright (c) 2008 André Luiz Alves Moraes
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
 */
import andre.grids.db.*;
import andre.grids.db.dataclasses.*;
import andre.grids.filesystem.common.*;
import andre.grids.filesystem.server.configuration.*;
import andre.grids.filesystem.server.directorymanagement.*;
import andre.grids.filesystem.server.filemanagement.*;
import andre.grids.network.*;
import andre.grids.util.log.*;
import com.db4o.*;
import java.io.*;
import java.util.*;
import org.apache.commons.codec.binary.*;

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
/**
 *
 * @author andre
 */
public class Main {

    public static void main(String[] args) {
        Locale brasil = new Locale("pt","BR");
        TimeZone tz = TimeZone.getTimeZone("GMT-0300");
        TimeZone.setDefault(tz);
        Locale.setDefault(brasil);
        
        System.out.println("Inicando: " + new Date(System.currentTimeMillis()).toString());
        
        boolean notRecognizedOption = true;
        try {        
            if (args[0].equals("clean"))
            {
                cleanUpThings();
                System.out.println(0);
                notRecognizedOption = false;
            }
            
            ConfigurationManager.loadServer(args[1]);
            
            if (args[0].equals("initdb"))
            {
                ConfigurationManager.initializeDb();
                System.exit(0);
            }
            
            if (args[0].equals("testbed"))
            {
                testBed(args);
                System.exit(0);
            }
            
            if (args[0].equals("rundm")) {
                runDmServer(args);
                notRecognizedOption = false;
            }
            
            if (args[0].equals("runfs")) {
                runFileServer(args);
                notRecognizedOption = false;
            }
            
            if (args[0].equals("sync")) {
                runSyncOperation(args);
            }
            
            if (notRecognizedOption)
            {
                System.out.println("Opção não reconhecida: " + args[0]);                
                System.exit(1);
            }
            
            System.out.println("System running");            
            
            long lastBeat = ConfigurationManager.getLastBeat();
            Calendar cal = Calendar.getInstance();
            while(true) {
                // gera um heart-beat a cada segundo
                ConfigurationManager.beat();
                
                Thread.sleep(1000);
            }
            
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    
    public static void runSyncOperation(String [] args) throws Exception {
        
                int year = Integer.parseInt(args[2]);
                int dayOfYear = Integer.parseInt(args[3]);
                int hour = Integer.parseInt(args[4]);
                int minute = Integer.parseInt(args[5]);
                
                Calendar cal = Calendar.getInstance();
                cal.set(Calendar.DAY_OF_YEAR, dayOfYear);
                cal.set(Calendar.HOUR_OF_DAY, hour);
                cal.set(Calendar.MINUTE, minute);
                cal.set(Calendar.SECOND, 0);
                cal.set(Calendar.YEAR, year);
                
                if (ConfigurationManager.isDmServer()) {
                    Log.debug("Carregando syncDm");
                    syncDm(cal.getTime());
                } else {
                    Log.debug("Carregando syncFs");
                    syncFs(cal.getTime());
                }        
                Log.debug("Fim da sincronização");
                System.exit(0);
    }
    
    public static void runDmServer(String [] args) throws Exception {
        DirectoryManagerImpl mng = new DirectoryManagerImpl();        
        DirectoryOperations dirOps = new DirectoryOperationsImpl();        
        FileOperations fileOps = new FileSystemOperationsProxy();
        
        mng.setMastersTable(MasterPeerTable.getInstance());
        
        // gerando o bind para as operações de diretorio
        RmiRegister.registerDirectoryObject(dirOps, ConfigurationManager.getBaseConfigInstance().getValue(ServerConfigurationProps.SERVER_DIROPS_RMI_BIND_NAME));
        // gerando o bind para as operações de arquivo
        RmiRegister.registerFileOperations(fileOps, ConfigurationManager.getBaseConfigInstance().getValue(ServerConfigurationProps.SERVER_FILEOPS_RMI_BIND_NAME));        
    }
    
    public static void runFileServer(String[] args) throws Exception {        
        FileOperations fileOps = new FileSystemOperationsImpl();        
        RmiRegister.registerFileOperations(fileOps, ConfigurationManager.getBaseConfigInstance().getValue(ServerConfigurationProps.SERVER_FILEOPS_RMI_BIND_NAME));
    }
    
    public static void syncDm(Date start) {
        
        Log.debug("Iniciando sincronização para: " + start);
        long currentBeat = System.currentTimeMillis();
        Date end = new Date(currentBeat);
        Log.debug("Terminando sincronização em: " + end);        
        Calendar cal = Calendar.getInstance();
        cal.setTime(start);
        
        while(start.before(end)) {
            Enumeration<PeerObjects> objs = MasterPeerTable.getInstance().getAllRemoteObjects();
            int dayOfYear = getDayOfYear(cal);
            int hour = getHour(cal);
            int minute = getMinute(cal);
            int year = getYear(cal);
            DbLogEntry [] entries = null;
            PeerObjects obj = null;
            LogLoader loader = new LogLoader();
            while(objs.hasMoreElements()) {
                try {
                    obj = objs.nextElement();                    
                    if (obj == null)
                        continue;
                    Log.debug("Carregando atualizações para: " + obj.getHost());
                    entries = obj.getDirectory().getLogSince(year,dayOfYear, hour, minute, 0);   
                    if (entries == null)
                        Log.logNormalOperation(Log.OP_TYPE_SYNC, "Sem atualizacoes: " + start.toString() + " no servidor: " + obj.getHost(), obj);
                    else
                        loader.loadAllLogs(entries);
                }
                catch(Exception e) {
                    Log.logException(e, objs);
                }
            }
            start = nextMinute(cal);
            cal.setTime(start);
        }
        // echo da última atualização feita no sistema
        ConfigurationManager.beat(start.getTime());
    }
    
    public static void syncFs(Date start) {
        long currentBeat = System.currentTimeMillis();
        Date end = new Date(currentBeat);
        Calendar cal = Calendar.getInstance();
        cal.setTime(start);
        Enumeration<PeerObjects> objs = MasterPeerTable.getInstance().getAllRemoteObjects();
        
        while(start.before(end)) {
            
            int dayOfYear = getDayOfYear(cal);
            int hour = getHour(cal);
            int minute = getMinute(cal);
            int year = getYear(cal);
            
            DbLogEntry [] entries = null;
            PeerObjects obj = null;
            LogLoader loader = new LogLoader();
            
            while(objs.hasMoreElements()) {
                try {
                    obj = objs.nextElement();
                    entries = obj.getFile().getLogSince(year, dayOfYear, hour, minute, 0);                    
                    loader.loadAllLogs(entries);
                }
                catch(Exception e) {
                    Log.logException(e, objs);
                }
            }
            
            start = nextMinute(cal);
            cal.setTime(start);
        }        
        ConfigurationManager.beat(start.getTime());
    }
    
    private static Date nextMinute(Calendar cal) {
        cal.add(Calendar.MINUTE, 1);
        cal.set(Calendar.SECOND, 0);
        cal.set(Calendar.MILLISECOND, 0);
        return cal.getTime();
    }
    
    private static int getDayOfYear(Calendar cal) {
        return cal.get(Calendar.DAY_OF_YEAR);
    }
    
    private static int getHour(Calendar cal) {
        return cal.get(Calendar.HOUR_OF_DAY);
    }
    
    private static int getMinute(Calendar cal) {
        return cal.get(Calendar.MINUTE);
    }
    
    private static int getYear(Calendar cal) {
        return cal.get(Calendar.YEAR);
    }
    
    public static void testBed(String[] args) {
        try {
            String testName = args[2];
            if (testName.equals("dumpdbpeer"))
                testDumpDbPeer();
            else if (testName.equals("createdir"))
                testDirectoryCreation();
            else if (testName.equals("dumpdir"))
                testDumpDbdirectory();
            else if (testName.equals("rmi"))
                testRmiConnection(args);
            else if (testName.equals("createfile"))
                testFileCreation(args);
        } catch(Exception e) {
            e.printStackTrace();
        }
    }
    
    public static void testDumpDbPeer() throws Exception {        
        DbPeerQueries query = new DbPeerQueries();
        java.util.Vector<DbPeer> data = query.getDirectoryMasters();
        for(DbPeer e: data) {
            System.out.println(e.getPeerName());
            System.out.println(e.isDirectoryMaster());
            System.out.println();
        }
    }
    
    public static void testDumpDbdirectory() throws Exception {
        DbDirectoryQueries query = new DbDirectoryQueries();
        DbDirectory[] all = query.listAll();
        for(DbDirectory dir: all) {
            System.out.println(dir.getDirName() + "\t" + dir.getDirOwner().getPeerName());
        }
    }

    public static void testDirectoryCreation() throws Exception {

//        DirectoryManagerImpl mng = new DirectoryManagerImpl();        
//        mng.setMastersTable(MasterPeerTable.getInstance());        
//        DirectoryOperations operations = new DirectoryOperationsImpl();        
//        FileOperations fileOps = new FileSystemOperationsImpl();
        
        runDmServer(null);
        
        DirectoryOperations operations = RmiRegister.getLocalDirectoryOperation();
        FileOperations fileOps = RmiRegister.getLocalFileOperations();
        
        
        operations.createDirectory("/");
        operations.createDirectory("/home");
        
        ObjectSet<DbDirectory> dirs = Database.getGridFsDb().getObjects().get(new DbDirectory());
        while(dirs.hasNext())
        {
            System.out.println(dirs.next().getDirName());
        }
        
        Database.getGridFsDb().closeDb();
        
    }

    public static void testDb() throws Exception {
        ObjectContainer db = Db4o.openFile("/home/andre/teste.db.db4o");
        DbPeer peer = new DbPeer();
        peer.setPeerName("teste");
        peer.setDirectoryMaster(true);
        db.set(peer);
        db.commit();
        db.close();
        System.out.println("OK");
    }
    
    public static void testRmiConnection(String [] args) throws Exception {
        System.out.println("Abrindo conexão com :" + args[3]);
        DirectoryOperations dirOp = MasterPeerTable.getInstance().getObjectsFor(args[3]).getDirectory();
        System.out.println("valor de retorno: " + dirOp.getDirectoryMaster("/"));
        System.out.println("Conexão efetuada e chamada respondida");
    }
    
    public static void testFileCreation(String [] args) throws Exception {
        System.out.println("Abrindo conexão com: " + args[3]);
        DirectoryOperations dirOp = MasterPeerTable.getInstance().getObjectsFor(args[3]).getDirectory();
        String [] result = dirOp.listContents("/");
        for(String s: result)
            System.out.println(result);
    }
    
    public static void cleanUpThings() throws Exception
    {
        File f = new File("/home/andre/griddb.db4o");
        f.delete();
        try
        {
        java.rmi.registry.Registry reg = java.rmi.registry.LocateRegistry.getRegistry("localhost", 10101);
        String[] binds = reg.list();
        java.util.Arrays.sort(binds);
        if (java.util.Arrays.binarySearch(binds, "FileOperations.rem")  >= 0)
            reg.unbind("FileOperations.rem");
        
        if (java.util.Arrays.binarySearch(binds, "DirectoryOperations.rem")  >= 0)
            reg.unbind("DirectoryOperations.rem");        
        }
        catch(Exception e)
        {
            System.exit(0);
        }
    }
}
